﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Windows.Forms;
using DevExpress.XtraBars;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using Moonlite.ExtensionApi.ControlInterfaces;
using Moonlite.ExtensionApi.GlobalInterfaces;
using Moonlite.Platform.General;
using Moonlite.Platform.Project;
using Moonlite.Services.CodeCompletion;

namespace Moonlite.UI.Shell.Controls
{
    public partial class FunctionExplorer : UserControl, IFunctionExplorer
    {
        private const string ConnectionString = "data source=\"Data\\GalaxyNatives.db\"";
        private SQLiteConnection connection = new SQLiteConnection(ConnectionString);
        public SQLiteConnection Connection
        {
            get { return connection; }
        }
        public static JassCodeObjectCollection JassNativeCode { get; private set; }
        public static GalaxyCodeObjectCollection GalaxyNativeCode { get; private set; }
        public List<object> Items
        {
            get
            {
                List<object> items = new List<object>();
                foreach (object item in listBox.Items)
                {
                    items.Add(item);
                }
                return items;
            }
        }

        private void Search()
        {
            try
            {
                if (Global.Instance != null && Global.Instance.Project != null)
                {
                    if (Global.Instance.Project.Type == ProjectType.Jass)
                    {
                        listBox.SelectedIndex = -1;
                        listBox.SelectionMode = SelectionMode.MultiExtended;
                        List<object> newItems = new List<object>();
                        List<object> removedItems = new List<object>();
                        int itemIndex = -1;
                        if (searchBox.EditValue == null || ((string)searchBox.EditValue).Length == 0)
                        {
                            return;
                        }

                        do
                        {
                            itemIndex = listBox.FindString((string)searchBox.EditValue, itemIndex);
                            if (itemIndex != -1)
                            {
                                object item = listBox.Items[itemIndex];
                                listBox.SetSelected(itemIndex, true);
                                listBox.Items.Remove(item);
                                removedItems.Add(item);
                                if (newItems.Contains(item) == false)
                                {
                                    newItems.Add(item);
                                }
                            }
                        } while (itemIndex != -1);

                        removedItems.ForEach(item =>
                        {
                            listBox.Items.Add(item);
                        });

                        newItems.ForEach(item =>
                        {
                            listBox.Items.Remove(item);
                            listBox.Items.Insert(0, item);
                        });

                        listBox.SelectedIndex = 0;
                    }
                    else if (Global.Instance.Project.Type == ProjectType.Galaxy)
                    {
                        listBox.Items.Clear();
                        SQLiteCommand command = null;
                        if (string.IsNullOrEmpty(((string)searchBox.EditValue)))
                        {
                            command = new SQLiteCommand("SELECT * FROM elements ORDER BY Name", connection);
                        }
                        else
                        {
                            string search = (string)searchBox.EditValue;
                            search = search.Replace("@", "@@");
                            search = search.Replace("_", "@_");
                            search = search.Replace("'", "\"");
                            command = new SQLiteCommand("SELECT * FROM elements WHERE name LIKE '%" + search + "%' ESCAPE '@' ORDER BY name", connection);
                        }
                        if (command != null)
                        {
                            SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                            DataTable dataTable = new DataTable("elements");
                            adapter.Fill(dataTable);
                            foreach (DataRow row in dataTable.Rows)
                            {
                                GalaxyCodeObject @object = new GalaxyCodeObject();
                                @object.Code = (string)row.ItemArray[1];
                                @object.Name = (string)row.ItemArray[0];
                                switch ((long)row.ItemArray[5])
                                {
                                    case 2:
                                        @object.Type = GalaxyCodeObjectType.Native;
                                        break;
                                    case 1:
                                        @object.Type = GalaxyCodeObjectType.Function;
                                        break;
                                    case 3:
                                    case 4:
                                        @object.Type = GalaxyCodeObjectType.Variable;
                                        break;
                                }
                                listBox.Items.Add(@object);
                            }
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Log += exception.Message;
            }
        }

        private void OnSearchBoxEditValueChanged(object sender, EventArgs e)
        {
            Search();
        }

        private void OnSearchItemClick(object sender, ItemClickEventArgs e)
        {
            Search();
        }

        private static int CompareJassCodeObjects(JassCodeObject a, JassCodeObject b)
        {
            if (a == null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == null)
            {
                throw new ArgumentNullException("b");
            }

            return a.Name.CompareTo(b.Name);
        }

        private static int CompareGalaxyCodeObjects(GalaxyCodeObject a, GalaxyCodeObject b)
        {
            if (a == null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == null)
            {
                throw new ArgumentNullException("b");
            }

            return a.Name.CompareTo(b.Name);
        }

        public void UpdateNativeCode()
        {
            listBox.Items.Clear();
            if (Global.Instance.Project.Type == ProjectType.Jass)
            {
                JassNativeCode.Sort(CompareJassCodeObjects);
                listBox.Items.AddRange(JassNativeCode.ToArray());
            }
            else
            {
                SQLiteCommand command = new SQLiteCommand("SELECT * FROM elements ORDER BY Name", connection);
                SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                DataTable dataTable = new DataTable("elements");
                adapter.Fill(dataTable);
                foreach (DataRow row in dataTable.Rows)
                {
                    GalaxyCodeObject @object = new GalaxyCodeObject();
                    @object.Code = (string)row.ItemArray[1];
                    @object.Name = (string)row.ItemArray[0];
                    switch ((long)row.ItemArray[5])
                    {
                        case 2:
                            @object.Type = GalaxyCodeObjectType.Native;
                            break;
                        case 1:
                            @object.Type = GalaxyCodeObjectType.Function;
                            break;
                        case 3:
                        case 4:
                            @object.Type = GalaxyCodeObjectType.Variable;
                            break;
                    }
                    listBox.Items.Add(@object);
                }
            }
        }

        private void OnListBoxSelectedIndexChanged(object sender, EventArgs e)
        {
            if (Global.Instance.Project == null)
            {
                return;
            }

            if (Global.Instance.Project.Type == ProjectType.Jass)
            {
                JassCodeObject codeObject = (JassCodeObject)listBox.SelectedItem;
                if (codeObject != null)
                {
                    ((ICodeExplorer)((object[])(Global.Instance.GetService(typeof(ICodeExplorer))))[0]).SetCode(codeObject.Code);
                }
            }
            else
            {
                GalaxyCodeObject codeObject = (GalaxyCodeObject)listBox.SelectedItem;
                if (codeObject != null)
                {
                    ((ICodeExplorer)((object[])(Global.Instance.GetService(typeof(ICodeExplorer))))[0]).SetCode(codeObject.Code);
                }
            }
        }

        public static void ReadNativeCode()
        {
            JassNativeCode = JassNativeCodeReader.Read();
            GalaxyNativeCode = GalaxyNativeCodeReader.Read();
        }

        public void OpenConnection()
        {
            connection.Open();
        }

        public void Clear()
        {
            listBox.Items.Clear();
        }

        private void OnSearchBoxRepositoryItemEditValueChanged(object sender, EventArgs e)
        {
            searchBox.EditValue = ((BaseEdit)sender).EditValue;
        }

        public FunctionExplorer()
        {
            InitializeComponent();
            try { Global.Instance.RegisterService(this, GetType().GetInterface("IFunctionExplorer")); }
            catch { }
        }
    }
}
